// Copyright Epic Games, Inc. All Rights Reserved.

#include "EditorWindow.h"
#include "EditorWindowStyle.h"
#include "EditorWindowCommands.h"
#include "LevelEditor.h"
#include "Widgets/Docking/SDockTab.h"
#include "Widgets/Layout/SBox.h"
#include "Widgets/Text/STextBlock.h"
#include "ToolMenus.h"
#include "ContentBrowserModule.h"
#include "WorkspaceMenuStructureModule.h"
#include "WorkspaceMenuStructure.h"
#include "EditorStyleSet.h"

static const FName EditorWindowTabName("EditorWindow");

#define LOCTEXT_NAMESPACE "FEditorWindowModule"

void FEditorWindowModule::StartupModule()
{
	// This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module

	FEditorWindowStyle::Initialize();
	FEditorWindowStyle::ReloadTextures();

	FEditorWindowCommands::Register();

	PluginCommands = MakeShareable(new FUICommandList);

	PluginCommands->MapAction(FEditorWindowCommands::Get().OpenPluginWindow,
	                          FExecuteAction::CreateRaw(this, &FEditorWindowModule::PluginButtonClicked),
	                          FCanExecuteAction());
	
	FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor");
	{
		// 创建菜单栏项
		// 创建拓展
		TSharedPtr<FExtender> MenuBarExtender = MakeShareable(new FExtender());
		/**
		@Param FName ExtensionHook. 项所在位置
		@Param EExtensionHook::Position HookPosition. 更具体的表示在ExtensionHook的相对位置：Before、After、First
		@Param const TSharedPtr< FUICommandList >& CommandList. 触发命令
		@Param const FMenuBarExtensionDelegate& MenuBarExtensionDelegate. 单播委托。绑定一个方法，方法是关于返回拓展项的信息。
		*/
		MenuBarExtender->AddMenuBarExtension("Help", EExtensionHook::After, PluginCommands,
		                                     FMenuBarExtensionDelegate::CreateRaw(
			                                     this, &FEditorWindowModule::AddMenuBarExtension));
		// 添加拓展项到关卡编辑器
		LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuBarExtender);
	}
	{
		// 创建菜单拓展项，就是菜单栏内的子项
		TSharedPtr<FExtender> MenuExtender = MakeShareable(new FExtender());
		MenuExtender->AddMenuExtension("WindowLayout", EExtensionHook::After, PluginCommands,
		                               FMenuExtensionDelegate::CreateRaw(this, &FEditorWindowModule::AddMenuExtension));
		LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(MenuExtender);
	}
	{
		// 创建工具栏拓展项
		TSharedPtr<FExtender> ToolBarExtender = MakeShareable(new FExtender());
		ToolBarExtender->AddToolBarExtension("Settings", EExtensionHook::After, PluginCommands,
		                                     FToolBarExtensionDelegate::CreateRaw(
			                                     this, &FEditorWindowModule::AddToolBarExtension));
		LevelEditorModule.GetMenuExtensibilityManager()->AddExtender(ToolBarExtender);

		// UToolMenu* ToolbarMenu = UToolMenus::Get()->ExtendMenu("LevelEditor.LevelEditorToolBar");
		// {
		// 	FToolMenuSection& Section = ToolbarMenu->FindOrAddSection("Settings");
		// 	{
		// 		FToolMenuEntry& Entry = Section.AddEntry(
    //               FToolMenuEntry::InitToolBarButton(FEditorWindowCommands::Get().OpenPluginWindow));
		// 		Entry.SetCommandList(PluginCommands);
		// 	}
		// }
	}
	{
		//在视口中被选中的actor与大纲视图的右键菜单中创建菜单
		//获取Viewport菜单上下文拓展项（Viewport中选中物体的右击菜单拓展项），是一个委托数组
		auto& LVCMExtenders = LevelEditorModule.GetAllLevelViewportContextMenuExtenders();
		//在数组中添加一个新的拓展项，当右击选中Actor并弹出菜单时，将会遍历此数组并执行绑定的委托方法
		LVCMExtenders.Add(FLevelEditorModule::FLevelViewportMenuExtender_SelectedActors::CreateRaw(this, &FEditorWindowModule::LVCMExtender));
	}

	FContentBrowserModule& ContentBrowserModule = FModuleManager::LoadModuleChecked<FContentBrowserModule>("ContentBrowser");
	{
		auto& ACMExtenders = ContentBrowserModule.GetAllAssetContextMenuExtenders();
		//添加因为拓展项委托
		ACMExtenders.Add(FContentBrowserMenuExtender_SelectedPaths::CreateRaw(this, &FEditorWindowModule::ACMExtender));
	}
	{
		auto& AVCMExtender = ContentBrowserModule.GetAllAssetViewContextMenuExtenders();
		AVCMExtender.Add(FContentBrowserMenuExtender_SelectedAssets::CreateRaw(this, &FEditorWindowModule::AVCMExtender));
	}

}

void FEditorWindowModule::ShutdownModule()
{
	// This function may be called during shutdown to clean up your module.  For modules that support dynamic reloading,
	// we call this function before unloading the module.

	UToolMenus::UnRegisterStartupCallback(this);

	UToolMenus::UnregisterOwner(this);

	FEditorWindowStyle::Shutdown();

	FEditorWindowCommands::Unregister();

	FGlobalTabmanager::Get()->UnregisterNomadTabSpawner(EditorWindowTabName);
}

TSharedRef<SDockTab> FEditorWindowModule::OnSpawnPluginTab(const FSpawnTabArgs& SpawnTabArgs)
{
	FText WidgetText = FText::Format(
		LOCTEXT("WindowWidgetText", "Add code to {0} in {1} to override this window's contents"),
		FText::FromString(TEXT("FEditorWindowModule::OnSpawnPluginTab")), FText::FromString(TEXT("EditorWindow.cpp")));

	return SNew(SDockTab).TabRole(ETabRole::NomadTab)[
		// Put your tab content here!
		SNew(SBox).HAlign(HAlign_Center).VAlign(VAlign_Center)[SNew(STextBlock).Text(WidgetText)]];
}

void FEditorWindowModule::PluginButtonClicked()
{
	FGlobalTabmanager::Get()->TryInvokeTab(EditorWindowTabName);
}

void FEditorWindowModule::AddMenuBarExtension(FMenuBarBuilder& Builder)
{
	Builder.AddMenuEntry(FEditorWindowCommands::Get().OpenPluginWindow);
	Builder.AddPullDownMenu(LOCTEXT("PullMenu", "PullMenu"), LOCTEXT("This_Is_Pull_Menu", "This is Pull Menu"),
	                        FNewMenuDelegate::CreateRaw(this, &FEditorWindowModule::AddMenuExtension), "AfterHelp");
}

void FEditorWindowModule::AddMenuExtension(FMenuBuilder& Builder)
{
	Builder.AddMenuEntry(FEditorWindowCommands::Get().OpenPluginWindow);
	//第一个参数是分隔栏的Hook名，第二参数是分隔栏的显示名称
	Builder.BeginSection("CustomSection", LOCTEXT("CustomArea", "CustomArea"));
	{
		//AddMenuEntry执行两遍，将在分隔栏添加两次拓展项
		Builder.AddMenuEntry(FEditorWindowCommands::Get().OpenPluginWindow);
		//创建简单的分割线
		Builder.AddMenuSeparator("SeparatorHook");
		Builder.AddMenuEntry(FEditorWindowCommands::Get().OpenPluginWindow);
		/**
		创建子下拉菜单，与创建下拉菜单相似，该方法有多个重载方法
		@Param 子下拉菜单的父拓展项的显示名称
		@Param 提示名称
		@Param 子下拉菜单项的委托
		@Param true-点击显示下拉菜单，false-鼠标移上去即显示下拉菜单
		@Param 显示图标，这里没有设置
		@Param 当一个子项被选择后，是否关闭子下拉菜单
		@Param Hook名称
		*/
		Builder.AddSubMenu(LOCTEXT("SubMenu", "SubMenu"), LOCTEXT("This_is_Sub_Menu", "This is Sub Menu!"),
                       FNewMenuDelegate::CreateRaw(this, &FEditorWindowModule::AddSubMenuExtension), false, FSlateIcon(),
                       true, "SubMenuHook");
	}
	Builder.EndSection();
}

void FEditorWindowModule::AddSubMenuExtension(FMenuBuilder& Builder)
{
	Builder.AddMenuEntry(FEditorWindowCommands::Get().OpenPluginWindow);
}

void FEditorWindowModule::AddToolBarExtension(FToolBarBuilder& Builder)
{
	//添加分隔栏，参数为Hook名称
	Builder.BeginSection("CustomHook");
	{
		Builder.AddToolBarButton(FEditorWindowCommands::Get().OpenPluginWindow);
		//添加分割线，参数为Hook名称
		Builder.AddSeparator("ToolBarSep");
		Builder.AddToolBarButton(FEditorWindowCommands::Get().OpenPluginWindow);
		Builder.AddToolBarButton(FEditorWindowCommands::Get().OpenPluginWindow);
		/**
		* 创建下拉菜单按钮，其实这个方法不止可以创建下拉菜单，主要是可以创建一个带有下拉图标的按钮
		*
		* @param   InAction                FUIAction类型，可以先通过其设置拓展项参数然后传给此方法调用，也可以直接设置下面的参数
		* @param   InMenuContentGenerator  当拓展项被触发，将会调用此委托，生成一个菜单
		* @param   InLabelOverride         标签显示名称，参数如果省略，将会使用Action中的参数
		* @param   InToolTipOverride       按钮提示名称，参数如果省略，将会使用Action中的参数
		* @param   InIconOverride          按钮图标，参数如果省略，将会使用Action中的参数
		* @param   bInSimpleComboBox       如果为true，标签和图标将不会被显示，默认为false
		* @param   InTutorialHighlightName 这个组件的标识名称，在教程说明中将会高亮显示，这个参数一般不用
		*/
		Builder.AddComboButton(FUIAction(), //拓展项的设置我们使用下面的参数去设置
                           FOnGetContent::CreateRaw(this, &FEditorWindowModule::ToolBarCombox), //绑定下面的UI委托方法
                           LOCTEXT("ComboBox", "ComboBox"), //标签内容
                           LOCTEXT("This_Is_ComboBox", "This is Combo Box!"), //提示信息
                           FSlateIcon(), //不使用图标
                           false //true-不显示图标和标签，false-显示图标和标签
    );
	}
	Builder.EndSection();
}

TSharedRef<SWidget> FEditorWindowModule::ToolBarCombox()
{
	TSharedPtr<SWidget> Combox = SNew(SBox).WidthOverride(150.f).HeightOverride(200.f)
      [
          SNew(SVerticalBox)+SVerticalBox::Slot().HAlign(HAlign_Fill).VAlign(VAlign_Top).AutoHeight()
          [
              SNew(STextBlock).Text(LOCTEXT("ThisComboBox", "This is Combo Box!"))
          ]+SVerticalBox::Slot().HAlign(HAlign_Fill).VAlign(VAlign_Top).AutoHeight()
          [
              SNew(SEditableTextBox)
          ]
      ];
	return Combox.ToSharedRef();
}

TSharedRef<FExtender> FEditorWindowModule::LVCMExtender(const TSharedRef<FUICommandList> CommandList, const TArray<AActor*> Actors)
{
	//加载LevelEditor模块
	// FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor");
	//创建一个拓展项，与上一章中用法相似，用其拓展菜单项
	TSharedPtr<FExtender> Extender = MakeShareable(new FExtender());
	//设置菜单拓展项显示内容，绑定的委托是上章创建的委托方法
	Extender->AddMenuExtension("ActorAsset", EExtensionHook::After, CommandList, FMenuExtensionDelegate::CreateRaw(this, &FEditorWindowModule::AddMenuExtension));
	// auto& LVCMExtenders = LevelEditorModule.GetAllLevelViewportContextMenuExtenders();
	// LVCMExtenders.Pop();          //如果将最后一个（我们刚刚创建的）Extender移除，则将会在第一显示菜单后，下次不会再显示此项
	//返回拓展项，将会被显示在菜单栏
	return Extender.ToSharedRef();
}

// 参数是用户右击鼠标时的目录地址，返回值是拓展项
TSharedRef<FExtender> FEditorWindowModule::ACMExtender(const TArray<FString>& Paths)
{
	//创建拓展项
	TSharedPtr<FExtender> Extender = MakeShareable(new FExtender());
	//设置拓展项参数，我们这里绑定了一个菜单项委托
	Extender->AddMenuExtension("ContentBrowserNewAdvancedAsset", EExtensionHook::After, PluginCommands, FMenuExtensionDelegate::CreateRaw(this, &FEditorWindowModule::AddMenuExtension));
	return Extender.ToSharedRef();
}

TSharedRef<FExtender> FEditorWindowModule::AVCMExtender(const TArray<FAssetData>& AssetData)
{
	TSharedPtr<FExtender> Extender = MakeShareable(new FExtender);
	// FContentBrowserModule& ContentBrowserModule = FModuleManager::LoadModuleChecked<FContentBrowserModule>("ContentBrowser");
	Extender->AddMenuExtension("CommonAssetActions", EExtensionHook::After, PluginCommands, FMenuExtensionDelegate::CreateRaw(this, &FEditorWindowModule::AddMenuExtension));
	return Extender.ToSharedRef();
}

#undef LOCTEXT_NAMESPACE

IMPLEMENT_MODULE(FEditorWindowModule, EditorWindow)
